package com.tqjc.business.interactivewithscan.uils;

import com.alibaba.fastjson.JSONObject;
import com.tqjc.business.interactivewithscan.consts.DateFormatConstant;
import com.tqjc.business.interactivewithscan.consts.ScadaExceptionEnum;
import com.tqjc.business.interactivewithscan.entity.DeviceAction;
import com.tqjc.business.interactivewithscan.entity.DeviceCommandData;
import com.tqjc.business.interactivewithscan.entity.DeviceSocketClient;
import com.tqjc.business.interactivewithscan.entity.ScadaCommandEntity;
import com.tqjc.business.interactivewithscan.exception.CustomException;
import com.tqjc.business.interactivewithscan.service.DeviceActionService;
import com.tqjc.system.core.util.SpringUtils;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @program: C20005_Xianggang_new
 * @description: Socket操作基础类
 * @author: Patienyon
 * @create: 2023-11-01 19:19
 **/

@Slf4j
public class SocketCommandUtils {

    /**
     * 设备动作主表 服务类
     */
    private static DeviceActionService actionService = SpringUtils.getBean(DeviceActionService.class);

    public static <T> T sendCommand(DeviceCommandData<T> data) {
        DeviceSocketClient socketClient = data.getSocketClient();
        synchronized (socketClient) {
            // 查询设备动作
            DeviceAction action = actionService.queryAction(socketClient.getDevice().getId(), data.getActionEnum().getActionCode());
            // 拼接命令
            // 命令
            String command = action.getCommand();
//            System.out.println("当前命令为"+command);
            String value = action.getValue();
            JSONObject values = JSONObject.parseObject(value);
            if (EmptyUtil.isEmpty(value)) {
                values = new JSONObject();
            }
            // 系统生成的值为最新
            if (!EmptyUtil.isEmpty(data.getDynamicValues())) {
                values.putAll(data.getDynamicValues());
            }
            // 动态命令拼接动态值
            command = dynamicValuesSplicing(command, values);
            if (action.getDeviceType() == 1) {
                ScadaCommandEntity commandEntity = new ScadaCommandEntity();
                commandEntity.setData(JSONObject.parseObject(command));
                commandEntity.setAction(action.getCommandType());
                command = JSONObject.toJSONString(commandEntity);
            }
            if (data.isLog()) {
                log.info("【" + data.getDevice().getDeviceName() + "】指定设备【" + socketClient.getDevice().getDeviceName() + "】下发【" + action.getOperationName() + "】命令：" + command);
            }
            //TODO:日志记录先屏蔽
//            printLogToFile(data.getDevice().getDeviceName(), "【" + data.getDevice().getDeviceName() + "】指定设备【" + socketClient.getDevice().getDeviceName() + "】下发【" + action.getOperationName() + "】命令：" + command);
            NetSocket socket = socketClient.getSocket();
            ArrayBlockingQueue<String> queue = new ArrayBlockingQueue(1);
            StringBuffer sb = new StringBuffer();
            if (action.getDeviceType().equals(2)) {
                socket.handler(h -> {
//                    System.out.println(h);
                    sb.append(h.toString());
                    if (sb.toString().endsWith(" kp")) {
                        queue.offer(sb.toString());
                    }
                });
            }
            socket.write(Buffer.buffer(command));

            if (action.getDeviceType().equals(1)) {
                socket.handler(h -> {
                    queue.offer(h.toString());
                });
            }

            String take = null;
            try {
                take = queue.poll(10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                queue.clear();
                printLogToFile(data.getDevice().getDeviceName(), "指定设备【" + socketClient.getDevice().getDeviceName() + "】响应【" + action.getOperationName() + "】超时！" + sb);
                throw new CustomException(ScadaExceptionEnum.SCADA_TIMEOUT_ERROR.setMsg("指定设备【" + socketClient.getDevice().getDeviceName() + "】响应【" + action.getOperationName() + "】超时！" + sb).setDeviceName(data.getDevice().getDeviceName()));
            }
            queue.clear();
            if (action.getDeviceType() == 1) {
                ScadaCommandEntity entity = JSONObject.parseObject(take, ScadaCommandEntity.class);
                if (EmptyUtil.isEmpty(entity)) {
                    throw new CustomException(ScadaExceptionEnum.SCADA_Command_ERROR.setMsg("指定设备【" + socketClient.getDevice().getDeviceName() + "】响应【" + action.getOperationName() + "】失败！").setDeviceName(data.getDevice().getDeviceName()));
                }
            }
            // TODO: 2022/1/13  打印响应命令日志
            if (data.isLog()) {
//                log.info("【" + data.getDevice().getDeviceName() + "】指定设备【" + socketClient.getDevice().getDeviceName() + "】接收【" + action.getOperationName() + "】的命令响应：" + take);
            }
            //TODO:暂时屏蔽日志写入
            printLogToFile(data.getDevice().getDeviceName(), "【" + data.getDevice().getDeviceName() + "】指定设备【" + socketClient.getDevice().getDeviceName() + "】接收【" + action.getOperationName() + "】的命令响应：" + take);
            //命令不需要响应结果
            if (EmptyUtil.isEmpty(action.getResultGoal())) {
                ScadaCommandEntity entity = JSONObject.parseObject(take, ScadaCommandEntity.class);
                if (entity.getData().size() > 0) {
                    throw new CustomException(ScadaExceptionEnum.SCADA_Command_ERROR.setMsg("指定设备【" + socketClient.getDevice().getDeviceName() + "】响应【" + action.getOperationName() + "】失败！").setDeviceName(data.getDevice().getDeviceName()));
                }
                return null;
            }
//            System.out.println(action);
//            System.out.println("当前数据为"+take);
            // 命令的响应结果
            if (action.getDeviceType() == 1) {
                System.out.println("命令已经响应");
                ScadaCommandEntity entity = JSONObject.parseObject(take, ScadaCommandEntity.class);
                T t = entity.getData().getObject(action.getResultGoal(), data.getRc());
                if (t == null) {
                    throw new CustomException(ScadaExceptionEnum.SCADA_Command_ERROR.setMsg("指定设备【" + socketClient.getDevice().getDeviceName() + "】响应【" + action.getOperationName() + "】失败！").setDeviceName(data.getDevice().getDeviceName()));
                }
                return t;
            } else if (action.getDeviceType() == 2) {
                return (T) take;
            }
            return null;
        }
    }

    /**
     * 动态命令拼接值
     *
     * @param command
     * @param json
     * @return
     */
    private static String dynamicValuesSplicing(String command, JSONObject json) {
        if (EmptyUtil.isEmpty(json)) {
            return command;
        }
        int start = command.indexOf("{{");
        if (start == -1) {
            return command;
        }
        int end = command.indexOf("}}");
        if (end == -1) {
            return command;
        }
        String name = command.substring(start + 2, end);
        if (EmptyUtil.isEmpty(name)) {
            return command;
        }
        Object o = json.get(name);
        if (EmptyUtil.isEmpty(o)) {
            return command;
        }
        command = command.replaceFirst("\\{\\{" + name + "}}", o.toString());
        command = dynamicValuesSplicing(command, json);
        return command;
    }

    //TODO:暂时屏蔽
    private static void printLogToFile(String deviceName, String msg) {
//        try {
//            Properties properties = System.getProperties();
//            String property = properties.getProperty("user.dir");
//            String today = DataTimeUtils.now(DateFormatConstant.DATE_GBK);
//            String filePath = property + "\\log\\" + today;
//            File file = new File(filePath);
//            if (!file.exists() && !file.isDirectory()) {
//                file.mkdir();
//            }
//            File file2 = new File(filePath + "\\【" + deviceName + "】" + today + ".log");
//            if (!file2.exists()) {
//                try {
//                    file2.createNewFile();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            FileOutputStream fo2 = new FileOutputStream(file2, true);
//            fo2.write((DataTimeUtils.now(DateFormatConstant.TIME_MS_GBK) + msg + "\t\n").getBytes(StandardCharsets.UTF_8));
//            fo2.flush();
//            fo2.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }
}
